import { CACHE_MANAGER, Cache } from "@nestjs/cache-manager";
import { ExecutionContext, UnauthorizedException, Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Reflector } from "@nestjs/core";
import { AuthGuard } from "@nestjs/passport";
import { Request } from "express";
import { ExtractJwt } from "passport-jwt";
import { PUBLIC_KEY, getAuthTokenKey } from "src/constant";

export interface MyRequset extends Request {
    user: RequsetUser;
}

@Injectable()
export class JwtGuard extends AuthGuard("jwt") {
    getAuthToken = ExtractJwt.fromAuthHeaderAsBearerToken();

    constructor(
        @Inject(CACHE_MANAGER) private cacheManager: Cache,
        private readonly configService: ConfigService,
        private reflector: Reflector,
    ) {
        super();
    }

    async canActivate(context: ExecutionContext) {
        const isPublic = this.reflector.getAllAndOverride<boolean>(PUBLIC_KEY, [context.getHandler(), context.getClass()]);

        let result: any = false;
        try {
            result = await super.canActivate(context);
        } catch (error) {
            if (isPublic) return true;
            throw error;
        }

        const request = context.switchToHttp().getRequest<MyRequset>();
        const token = this.getAuthToken(request);

        if (!this.configService.get<boolean>("MULTI_DEVICE_LOGIN")) {
            const cacheToken = await this.cacheManager.get<string>(getAuthTokenKey(request.user.id));
            if (token != cacheToken) throw new UnauthorizedException("您的账号已在其他地方登录");
        }

        return result;
    }
}
